package org.rollinitiative.d20tools.arena;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.rollinitiative.d20.combat.Action;
import org.rollinitiative.d20.combat.Allegiance;
import org.rollinitiative.d20.combat.Combatant;
import org.rollinitiative.d20.combat.TurnProcessor;
import org.rollinitiative.d20.dice.Dice;
import org.rollinitiative.d20.encounter.Encounter;
import org.rollinitiative.d20.entity.Ability;
import org.rollinitiative.d20.entity.Actor;
import org.rollinitiative.d20.entity.CharacterBridge;
import org.rollinitiative.d20.entity.CharacterFactory;
import org.rollinitiative.d20.entity.Player;
import org.rollinitiative.d20.entity.RaceContentBridge;
import org.rollinitiative.d20.entity.classes.ClassContentBridge;
import org.rollinitiative.d20.entity.skills.SkillsContentBridge;
import org.rollinitiative.d20.schema.character.CharacterType;

public class Arena
{
    final static Log LOG_ = LogFactory.getLog(Arena.class);

    static XMLConfiguration config_;

    protected Dice dice = Dice.getInstance();

    protected Encounter encounter = null;

    protected ArrayList<Actor> playerList = new ArrayList<Actor>();

    protected ArrayList<Actor> partyList = new ArrayList<Actor>();

    protected ArrayList<Actor> hostileList = new ArrayList<Actor>();

    protected int partyHPs = 0;

    protected int hostileHPs = 0;

    protected HashMap<Actor, String> actorStats = new HashMap<Actor, String>();

    CharacterBridge characterBridge;

    CharacterFactory characterFactory_;


    public Encounter getEncounter()
    {
        return encounter;
    }


    public ArrayList<Actor> getPlayerList()
    {
        return playerList;
    }


    public ArrayList<Actor> getPartyList()
    {
        return partyList;
    }


    public ArrayList<Actor> getHostileList()
    {
        return hostileList;
    }


    public void setupEncounter()
    {
        encounter = new Encounter("Test");

        // Assemble the party
        String partyMode = config_.getString("arena.party[@mode]");
        LOG_.info("partyMode = " + partyMode);
        if (partyMode.equalsIgnoreCase("xmldb")) {
            loadParty(config_.getString("arena.party.collection"));
        }
        else {
            generateParty();
        }

        Actor direRat = new Player("NPC", "Rat1");
        direRat.getHitPoints().advanceLevel(randomHP(1));
        hostileList.add(direRat);

        direRat = new Player("NPC", "Rat2");
        direRat.getHitPoints().advanceLevel(randomHP(1));
        hostileList.add(direRat);

        direRat = new Player("NPC", "Rat3");
        direRat.getHitPoints().advanceLevel(randomHP(1));
        hostileList.add(direRat);
        //
        // direRat = new Player("NPC", "Rat4");
        // direRat.randomHP(1);
        // hostileList.add(direRat);

        playerList.addAll(partyList);
        playerList.addAll(hostileList);

        Object[] hostiles = hostileList.toArray();
        for (int i = 0; i < hostiles.length; i++) {
            encounter.joinEncounter((Actor) hostiles[i], Allegiance.PARTY);
        }

        encounter.initiate();
    }


    public Actor getPartyDefender()
    {
        int index = (int) (Math.random() * partyList.size());
        return partyList.get(index);
    }


    public Actor getHostileDefender()
    {
        int index = (int) (Math.random() * hostileList.size());
        return hostileList.get(index);
    }


    public Actor getStrongestHostileDefender(Actor attacker)
    {
        Actor actor = null;
        int maxIndex = 0;

        for (int i = 1; i < hostileList.size(); i++) {

            if (hostileList.get(i).getHP() > hostileList.get(i - 1).getHP())
                maxIndex = i;
        }
        actor = hostileList.get(maxIndex);

        return actor;
    }


    public Actor getWeakestHostileDefender(Actor attacker)
    {
        Actor actor = null;
        int minIndex = 0;

        for (int i = 1; i < hostileList.size(); i++) {
            Actor hostile = hostileList.get(i);

            if (hostileList.get(i).getHP() < hostileList.get(i - 1).getHP())
                minIndex = i;
        }
        actor = hostileList.get(minIndex);

        return actor;
    }


    public void printHPs()
    {
        partyHPs = 0;
        hostileHPs = 0;

        System.out.println();
        Object[] party = playerList.toArray();
        for (int i = 0; i < party.length; i++) {
            Actor actor = (Actor) party[i];
            String stats = actorStats.get(actor);
            if (stats == null)
                stats = "";
            if ((actor.getHP() >= 0) && (actor.getHP() < 10))
                stats += " ";
            stats += " " + actor.getHP();
            actorStats.put(actor, stats);
            System.out.println(actor.getName() + "\t:" + stats + " /" + actor.getMaxHP());

            if (actor.getHP() > 0) {
                if (partyList.contains(actor))
                    partyHPs += actor.getHP();
                if (hostileList.contains(actor))
                    hostileHPs += actor.getHP();
            }
        }
        System.out.println();
    }


    public boolean execute()
    {
        // TurnProcessor turnProc = TurnProcessor.getInstance();

        while (true) {
            encounter.executeRound();
            printHPs();
            if (partyHPs <= 0) {
                System.out.println("Party LOSES!");
                return false;
            }
            else if (hostileHPs <= 0) {
                System.out.println("Party WINS!");
                return (true);
            }

            // Iterator<Combatant> combatants = encounter.getInitiativeOrder();
            // while (combatants.hasNext()) {
            // Combatant nextCombatant = combatants.next();
            // if (nextCombatant.getActor().getHP() > 0) {
            // System.out.println("Next up is "
            // + nextCombatant.getActor().getName());
            //
            // // retrieve and execute actions selected by the combatant
            // turnProc.process(this, nextCombatant);
            //
            // printHPs();
            //				
            // if (partyHPs <= 0) {
            // System.out.println("Party LOSES!");
            // return false;
            // } else if (hostileHPs <= 0) {
            // System.out.println("Party WINS!");
            // return(true);
            // }
            // }
            // }
        }
    }


    public static void main(String[] args) throws Exception
    {
        PropertyConfigurator.configure("log4j.config");
        // Load the configuration file
        try {
            config_ = new XMLConfiguration("arena.config.xml");
        } catch (ConfigurationException configEx) {
            LOG_.fatal("FAILED to load configuration file: config.xml");
        }

        int max = 1;
        int total = 0;

        for (int i = 0; i < max; i++) {
            Arena arena = new Arena();
            arena.init();
            arena.setupEncounter();
            boolean partyWins = arena.execute();
            if (partyWins)
                total += 1;
        }
        System.out.println("Percent Party Wins = " + total + "/" + max);
    }


    void loadParty(String partyTag)
    {
        characterBridge.loadCollection("arena", partyTag);
        CharacterType characters[] = characterBridge.getGroup("party");
        LOG_.debug("total number of characters in party = " + characters.length);
        for (int i = 0; i < characters.length; i++) {
            Actor partyMember = null;
            try {
                partyMember = characterFactory_.load(characters[i]);

                // TODO This is a temporary randomization of hp and BAB.
                // partyMember.randomHP(6);
                //partyMember.setMaxBaseAttackBonus(6);
                partyList.add(partyMember);
                encounter.joinEncounter(partyMember, Allegiance.PARTY);
            } catch (Exception e) {
                continue;
            }
        }
    }


    void generateParty()
    {
        Actor zephar = new Player("Player 1", "Zephar");
        zephar.setAbilityBaseValue(Ability.DEX, 14);
        zephar.getHitPoints().advanceLevel(randomHP(3));
        partyList.add(zephar);

        Actor flint = new Player("Player 2", "Flint");
        flint.setAbilityBaseValue(Ability.STR, 18);
        zephar.getHitPoints().advanceLevel(randomHP(5));
        partyList.add(flint);

        Object[] party = partyList.toArray();
        for (int i = 0; i < party.length; i++) {
            encounter.joinEncounter((Actor) party[i], Allegiance.PARTY);
        }
    }
    
    // temporary...
    int randomHP(int factor)
    {
        return 1 + (int)(10.0 * Math.random()) * factor;
    }


    void init()
    {
        // Configure bridges to content.
        RaceContentBridge raceBridge = new RaceContentBridge(config_);
        raceBridge.loadCollection("arena");
        characterBridge = new CharacterBridge(config_);

        ClassContentBridge classBridge = new ClassContentBridge(config_);
        classBridge.loadCollection("arena");
        
        SkillsContentBridge skillBridge = new SkillsContentBridge(config_);
        skillBridge.loadCollection("arena");

        // Configure CharacterFactory
        characterFactory_ = new CharacterFactory();
        characterFactory_.setClassContentBridge(classBridge);
        characterFactory_.setRaceContentBridge(raceBridge);
        characterFactory_.setSkillBridge(skillBridge);
    }
}
